﻿
using BaseUtils.Helper;
using BaseUtils.Logger;
using DatabaseCore.Modal;
using DeviceManage.PLC;
using Newtonsoft.Json;
using NWMES;
using Service.src.Flow.JavaScript;
using Service.src.NW.Enum;
using Service.src.NW.Model;
using Service.src.NW.Model.Enum;
using Service.src.NW.Model.Folw;
using Service.src.NW.Processor.Core;
using Service.src.NW.Processor.Core.Connector;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace Service.src.Model.Folw
{
    /// <summary>
    /// 节点根，包含节点的所有信息和触发入口
    /// </summary>
    public class NodeProcessor : RuntimeParam
    {

        //[JsonIgnore]
        //public int flowId { get; set; }
        /// <summary>
        /// </summary>
        //[JsonIgnore]
        //public NodeTypeEnum _NodeType { get; set; }

        /// <summary>
        /// 被clone节点id，clone是临时使用
        /// </summary>
        [JsonIgnore]
        public int CloneNodeTempId { get; set; }

        /// <summary>
        /// 子节点
        /// </summary>
        [JsonIgnore]
        public List<NodeProcessor> Children { get; set; } = new List<NodeProcessor>();

        /// <summary>
        /// 父节点
        /// </summary>
        [JsonIgnore]
        public List<NodeProcessor> Parents { get; set; } = new List<NodeProcessor>();

        /// <summary>
        /// 扁平化的所有父节点数据
        /// </summary>
        [JsonIgnore]
        public Dictionary<int, NodeProcessor> ParentKeyValue { get; set; } = new Dictionary<int, NodeProcessor>();

        /// <summary>
        /// 当前节点执行状态
        /// </summary>
        [JsonIgnore]
        public TaskCompletionSource<bool> ExecutionSource { get; set; } = new TaskCompletionSource<bool>();
        //[JsonIgnore]
        //public bool ExecutionSource { get; set; } = false;

        /// <summary>
        /// 当前节点执行结束之后的值
        /// </summary>
        [JsonIgnore]
        public IPLCHelper PLCDevice { get; set; }

        /// <summary>
        /// 执行节点
        /// </summary>
        /// <returns></returns>
        public async Task ExecuteNode(long FlowId)
        {

            if (!AppData.Runings.ContainsKey(FlowId))
            {
                LoggerService.Info("流程已结束");
                return;
            }

            _FlowId = FlowId;
            //string json = System.Text.Json.JsonSerializer.Serialize(Parents);
            // 等待所有上级节点执行完毕
            foreach (NodeProcessor parent in Parents)
            {
                await parent.ExecutionSource.Task;
            }
            if (id == 2145)
            {
             // Console.Write("2");
            }
            // long sss = DateTimeOffset.Now.ToUnixTimeMilliseconds();
            bool iti = IsTrigger();

            if (!iti)
            {
                AppData.RemoveRunCompleteNodeId(FlowId, this.id);
            }
            bool EndCurrentNode = this.NodeInputParam?.IsNodeContinue ?? true;
            if (iti)
            {
                NodeStart(this);
                RunNodeParams(this);
            }
            //if (iti)
            //{
            // 执行当前节点
            // Console.WriteLine($"Executing {name} ({id})");
            // 节点开始执行时间
            // todo 以下代码将弃用,节点完成事件将在对应的节点线程中处理
            List<NodeTypeEnum> Ignores = new List<NodeTypeEnum>() {
                NodeTypeEnum.SOCKET_CLIENT,
                NodeTypeEnum.FILE_IO_READ,
                NodeTypeEnum.PLC_READ,
                NodeTypeEnum.PLC_WRITE,
                NodeTypeEnum.MES_MiFindCustomAndSfcData,
                NodeTypeEnum.MES_MachineIntegration,
                NodeTypeEnum.MES_MiReleaseSfcWithActivity,
                NodeTypeEnum.LOGIC_TRIGGER_FLOW,
                NodeTypeEnum.DATABASE,
            };
       
            if (!Ignores.Contains(nodeType) && EndCurrentNode && BaseProcessor.NodeComplete(this))
            {
                // 递归执行子节点
                foreach (var child in Children)
                {
                    try
                    {
                        bool Runing = AppData.RuningNodes?[FlowId]?.Contains(child.id) ?? false;
                        if (child.NodeStatus != NodeStatusEnum.DEFAULT || Runing)
                        {
                            continue;
                        }
                    }
                    catch (Exception ex)
                    {
                        LoggerService.Info($"节点异常：{child.id}，{child.name}，原因：{ex.Message}", ex);
                    }

                    if (NodeStatus != NodeStatusEnum.STATIC_EXECUTION)
                    {
                        AppData.AddRuningNodeId(FlowId, child.id);
                        LoggerService.Info($"当前节点：{child.id}，{child.name}");
                    }
                    try
                    {
                        Task _child = child.ExecuteNode(FlowId); // fire and forget
                        if (_child.Status == TaskStatus.Faulted)
                        {
                            string ExecuteNodeErrorMessage = _child.Exception?.ToString();
                            if (!string.IsNullOrEmpty(ExecuteNodeErrorMessage))
                            {
                                BaseProcessor.SendNodeLoggerError(child, ExecuteNodeErrorMessage);
                            }
                            child.NodeStatus = NodeStatusEnum.ERROR;
                            BaseProcessor.Complete(child, NodeStatusEnum.ERROR);
                        }
                    }
                    catch (Exception ex)
                    {
                        child.NodeStatus = NodeStatusEnum.ERROR;
                        BaseProcessor.Complete(child, NodeStatusEnum.ERROR);
                        LoggerService.Error($"节点执行异常，节点id：{child.id},原因：{ex.Message}", ex);
                    }
                }
                AppData.RemoveRunCompleteNodeId(FlowId, id);
            }
            else
            {
                if (NodeStatus == NodeStatusEnum.STATIC_EXECUTION)
                {
                    foreach (var child in Children)
                    {
                        try
                        {
                            Task _child = child.ExecuteNode(FlowId);
                            if (_child.Status == TaskStatus.Faulted)
                            {
                                child.NodeStatus = NodeStatusEnum.ERROR;
                                BaseProcessor.Complete(child, NodeStatusEnum.ERROR);
                            }
                        }
                        catch (Exception ex)
                        {
                            child.NodeStatus = NodeStatusEnum.ERROR;
                            BaseProcessor.Complete(child, NodeStatusEnum.ERROR);
                            LoggerService.Error($"节点执行异常，节点id：{child.id},原因：{ex.Message}", ex);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// 为满足节点结束条件
        /// 继续运行当前节点
        /// 
        /// 一般只有在读取plc值的节点中使用，
        /// 读取的值不是结束值，就循环遍历的读，直到条件成立
        /// </summary>
        /// <param name="FlowId"></param>
        /// <param name="EndCurrentNode"></param>
        private void ContinueRunningCurrentNode(long FlowId, bool EndCurrentNode)
        {
            Task.Run(() =>
            {
                while (!EndCurrentNode && AppData.Runings.ContainsKey(FlowId))
                {
                    RunNodeParams(this);
                    Thread.Sleep(100);
                }
            });
        }

        /// <summary>
        /// 判断是否能继续触发当前节点
        /// 是否触发节点
        /// </summary>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        private bool IsTrigger()
        {
            if (id == 2145)
            {
                Console.Write("2");
            }
            bool iti = false;
            int is2 = Parents?.Count ?? 0;
            if (this.enable == 0) // 节点被禁用时，直接返回，不执行
            {
                return iti;
            }
            iti = is2 <= 0;
            if (iti)
            {
                return iti;
            }
            if (Parents.Where(p => p.NodeStatus == NodeStatusEnum.STATIC_EXECUTION).Count() == is2)
            {
                BaseProcessor.SetNodeOutParamValue(this, NodeOutParamNameEnum.NODE_STATUS, NodeStatusEnum.STATIC_EXECUTION);
                ExecutionSource.SetResult(true); // 不符合条件的也要给结果赋值
                if ( id == 2185)
                {
                    //Console.Write("2");
                }
                
                return false;
            }

            foreach (NodeProcessor Parent in Parents)
            {
                if (iti)
                {
                    break;
                }
                if (Parent.nodeType == NodeTypeEnum.LOGIC_SWITCH)
                {
                    if (Parent.NodeInputParam == null)
                    {
                        break;
                    }
                    if (Parent?.NodeInputParam?.NodeLogic?.Ranges.Any() == true)
                    {
                        foreach (RangeCondition item in Parent?.NodeInputParam?.NodeLogic?.Ranges)
                        {
                            if (item.TriggerNodeId == this.id && item.IsTrigger)
                            {
                                iti = true;
                                break;
                            }
                        }
                    }

                }
                else
                {
                    iti = true;
                }
            }
            if (!iti)
            {
                //NodeStatus = NodeStatusEnum.STATIC_EXECUTION;
                BaseProcessor.SetNodeOutParamValue(this, NodeOutParamNameEnum.NODE_STATUS, NodeStatusEnum.STATIC_EXECUTION);
                if (!ExecutionSource.Task.IsCompleted)
                {
                    ExecutionSource.SetResult(true); // 不符合条件的也要给结果赋值
                }
            }
            return iti;
        }

        /// <summary>
        /// 节点开始执行
        /// </summary>
        /// <param name="nodeProcessor"></param>
        private void NodeStart(NodeProcessor nodeProcessor)
        {
            stopwatch.Start();
            try
            {
                JavaScriptEvent.Send(JavaScriptEventEnum.NODE_START, nodeProcessor);
            }
            catch (Exception ex)
            {
                // Console.WriteLine(ex);
            }
            BaseProcessor.SendNodeLoggerInfo(nodeProcessor, $"节点开始！");
            Code = 1;
            if (nodeProcessor.NodeTimeOut > 0)
            {
                _ = Task.Run(() =>
                {
                    long PID = nodeProcessor._FlowId;
                    Thread.Sleep(nodeProcessor.NodeTimeOut);
                    if (AppData.RuningNodes.ContainsKey(PID) && AppData.RuningNodes[PID].Contains(nodeProcessor.id))
                    {
                        AppData.RemoveRunCompleteNodeId(PID, nodeProcessor.id);
                        BaseProcessor.Complete(nodeProcessor, NodeStatusEnum.ERROR);
                        BaseProcessor.SendNodeLoggerError(nodeProcessor, $"节点ID={nodeProcessor.id}，执行时间超时，已自动结束，节点设置的等待时间{nodeProcessor.NodeTimeOut}/ms");
                    }
                });
            }
        }

        /// <summary>
        /// 处理节点逻辑
        /// </summary>
        /// <param name="nodeProcessor"></param>
        private void RunNodeParams(NodeProcessor nodeProcessor)
        {
            if (nodeProcessor.NodeInputParam == null)
            {
                nodeProcessor.NodeInputParam = new NodeInputParam();
            }
            nodeProcessor.NodeInputParam.IsNodeContinue = true;
            NodeInputParam InputParam = nodeProcessor.NodeInputParam;
            switch (nodeProcessor.Group)
            {
                // todo 后期优化 读写 操作，整合成 发送和接收，如给plc发送，给全局变量发送，给socket等客户端发送数据，接收数据同理
                case GroupTypeEnum.PLC:
                    if (InputParam.NodePLC == null)
                    {
                        BaseProcessor.SendNodeLoggerError(nodeProcessor, $"{nodeProcessor.id}参数配置异常,未配置的参数 ", RuntimeErrorCodeEnum.NODE_INPUT_PARAM_NULL);
                        BaseProcessor.Complete(nodeProcessor, NodeStatusEnum.ERROR);
                        return;
                    }
                    if (InputParam.NodePLC.DataSourceId == -99)
                    {
                        GlobalParamProcessor.Run(nodeProcessor, InputParam);
                    }
                    else
                    {
                        PlcProcessor.Run(nodeProcessor, InputParam);
                    }
                    break;
                case GroupTypeEnum.MES:
                    MesProcessor.Run(nodeProcessor, InputParam);
                    break;
                case GroupTypeEnum.LOGIC:
                    LogicProcessor.Run(nodeProcessor, InputParam);
                    break;
                case GroupTypeEnum.SOCKET:
                    SocketProcessor.Run(nodeProcessor, InputParam);
                    break;
                case GroupTypeEnum.FILE_IO:
                    FileIOProcessor.Run(nodeProcessor, InputParam);
                    break;
                case GroupTypeEnum.CONNECTOR:
                case GroupTypeEnum.DATABASE:
                    ConnectorProcessor.Run(nodeProcessor, InputParam);
                    break;
            }
        }

        /// <summary>
        /// 设置节点的可输出参数
        /// 默认时使用
        /// </summary>
        /// <param name="flow"></param>
        /// <param name="param"></param>
        /// <exception cref="NotImplementedException"></exception>
        public void SetNodeOutParamName()
        {
            NodeOutParam OutParams = new NodeOutParam();
            //OutParams.AddOutParam(NodeOutParamNameEnum.NODE_STATUS.ToString(), "int");
            if (nodeType == NodeTypeEnum.PLC_READ)
            {
                foreach (NodeInputPlcReadParam item in NodeInputParam?.NodePLC?.ReadParams ?? new List<NodeInputPlcReadParam>())
                {
                    OutParams.AddOutParam(item.ParamName, item.ValueType);
                }
                OutParams.AddOutParam(NodeOutParamNameEnum.DEVICE_READ_RESULT.ToString(), "list");
            }
            if (nodeType == NodeTypeEnum.DB_MY_SQL)
            {
                OutParams.AddOutParam<DBResult>(new DBResult());
            }
            if (nodeType.ToString().StartsWith("MES_"))
            {
                OutParams.AddOutParam<MesResult>(new MesResult());
            }
            if (nodeType == NodeTypeEnum.LOGIC_USER_SCRIPT)
            {
                OutParams.AddOutParam(NodeInputParam?.NodeLogic?.Script?.OutParams);
            }
            if (nodeType == NodeTypeEnum.SOCKET_CLIENT)
            {
                OutParams.AddOutParam(NodeOutParamNameEnum.DEVICE_READ_RESULT.ToString(), "string");
            }
            if (nodeType == NodeTypeEnum.FILE_IO_READ)
            {
                OutParams.AddOutParam(NodeOutParamNameEnum.DEVICE_READ_RESULT.ToString(), "string");
            }
            if (nodeType == NodeTypeEnum.LOGIC_CALCULATOR)
            {
                foreach (NodeDataSource item in NodeInputParam?.NodeLogic?.Calculator?.InputParams ?? new List<NodeDataSource>())
                {
                    OutParams.AddOutParam(item.TargetParamName, item.ValueType);
                }
            }
            if (nodeType == NodeTypeEnum.SERIAL_PORT)
            {
                OutParams.AddOutParam(NodeOutParamNameEnum.DEVICE_READ_RESULT.ToString(), "string");
            }
            NodeOutParam = OutParams;
        }

        public NodeProcessor Copy()
        {
            return ConvertHelper.ToObject<NodeProcessor>(this.ToJson());
        }

    }
}
